package com.atguigu.gulimall.product.config;

import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

/**
 * @create: 2024/8/31
 * @author: gyhe10
 * @description: 自定义 RedisCacheConfiguration
 **/

// @EnableCaching// 开启缓存功能，任意配置类上添加即可，主启动类上已添加，所以这里不需要添加
@EnableConfigurationProperties({CacheProperties.class})// 激活 Spring Cache 的配置属性类 CacheProperties，将 CacheProperties 交给 Spring 容器管理
// @Configuration
public class MyRedisCacheConfiguration {

    /**
     * 自定义 RedisCacheConfiguration
     * @EnableConfigurationProperties 注解的作用：
     *      1. 自动注册配置类：当一个配置类使用了 @ConfigurationProperties 注解，并且希望这个配置类能够被 Spring 容器管理时，可以通过添加 @EnableConfigurationProperties 注解来自动注册这些配置类。这意味着，即使配置类没有使用 @Component 注解，也可以被 Spring 容器识别并实例化。
     *      2. 绑定配置文件属性：配合 @ConfigurationProperties 注解，@EnableConfigurationProperties 可以帮助将配置文件中的属性值绑定到指定的 Java 对象上。这样就可以方便地在应用中使用这些配置属性。
     *      3. 条件化加载：@EnableConfigurationProperties 可以接受一个或多个 @ConfigurationProperties 类型参数，指示哪些配置类应该被激活。此外，还可以与其他注解（如 @ConditionalOnClass、@ConditionalOnProperty 等）一起使用，实现基于条件的配置加载。
     * @param cacheProperties 已经将 CacheProperties 交给 Spring 容器管理，所以可以在 @Bean 方法中直接使用，不需要再使用 @Value 注解获取配置文件中的配置，或者 @Autowired 注解来注入
     *                        当一个 @Bean 方法声明了一个依赖项（即作为参数传递的另一个 Bean），Spring 容器会在调用该 @Bean 方法之前确保依赖项已经被创建并且可用。这是因为 Spring 容器遵循依赖注入的原则，它会自动处理依赖关系
     * @return
     */
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        // 默认配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        // 使用配置文件的配置覆盖默认配置
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();

        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }

        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
        }

        // 设置是否缓存 null 值，配置文件中设置允许缓存 null 值，因此这里 if 判断为 false，也就是使用默认配置，允许缓存 null 值
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }

        // 设置是否使用 key 前缀，配置文件中设置允许使用 key 前缀，因此这里 if 判断为 false，也就是使用默认配置，使用 key 前缀
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }

        // 缓存的 key 使用 StringRedisSerializer 序列化器，默认使用 StringRedisSerializer，所以可以不做配置
        // config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));

        // 缓存的 value 使用 GenericJackson2JsonRedisSerializer 序列化器
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return config;
    }
}
